package modelo;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class Servidor implements AutoCloseable {
	public static final int PORTA = 14400;
	public static Servidor instanciaServidor;
	private ServerSocket servidor;
	private List<OutputStream> canaisClientesConectados;
	private List<String> clientesConectados;
	private HashMap<String, OutputStream> relacaoClientesConectados;
	
	// TODO
	// discutir alguma estrutura para o servidor ter conhecimento de todos os
	// clientes conectados

	public Servidor() throws IOException {
		this.servidor = new ServerSocket(PORTA);
		this.canaisClientesConectados = new ArrayList<OutputStream>();
		this.clientesConectados = new ArrayList<String>();
		this.relacaoClientesConectados = new HashMap<String, OutputStream>();
	}
	
	public static Servidor getInstanciaServidor() throws IOException {
		if(instanciaServidor == null) instanciaServidor = new Servidor();
		return instanciaServidor;
	}
	
	private synchronized void enviaMensagemClienteX(String tipoMensagem, OutputStream clienteX, String mensagem, String membrosConversa) throws IOException {
		DataOutputStream saida = new DataOutputStream(clienteX);
		saida.writeBytes(tipoMensagem + "\n");
		saida.writeBytes(membrosConversa + "\n");
		saida.writeBytes(mensagem + "\n");
		
		saida.close();
	}
	
	private synchronized void enviaListaClienteX(String tipoMensagem, OutputStream clienteX, String lista) throws IOException {
		DataOutputStream saida = new DataOutputStream(clienteX);
		saida.writeBytes(tipoMensagem + "\n");
		saida.writeBytes(lista + "\n");
		
		saida.close();
	}
	
	public synchronized void enviaParaClienteX(String tipoMensagem, String mensagem, String receptor, String membrosConversa) throws IOException {
		if(tipoMensagem.equals("lista")) {
			enviaListaClienteX(tipoMensagem, relacaoClientesConectados.get(receptor), mensagem);
		}
		else if(tipoMensagem.equals("mensagem")) {
			enviaMensagemClienteX(tipoMensagem, relacaoClientesConectados.get(receptor), mensagem, membrosConversa);
		}
		else if(tipoMensagem.equals("encerramento")) {
			enviaMensagemEncerramento(tipoMensagem, relacaoClientesConectados.get(receptor));
		}
	}
	
	public void enviaMensagemEncerramento(String tipoMensagem, OutputStream clienteX) throws IOException {
		DataOutputStream saida = new DataOutputStream(clienteX);
		saida.writeBytes(tipoMensagem + "\n");
		
		saida.close();
		servidor.close();
	}
	
	public void removeClienteX(String clienteX) {
		clientesConectados.remove(clienteX);
		canaisClientesConectados.remove(relacaoClientesConectados.get(clienteX));
		relacaoClientesConectados.remove(clienteX);
	}
	
	public synchronized boolean verificaExistenciaNome(String nomeCliente, OutputStream outputCliente) {
		boolean contemNome = this.getClientesConectados().contains(nomeCliente);
		
		if(contemNome == false) {
			//essa linha nao vai precisar
			clientesConectados.add(nomeCliente);
			relacaoClientesConectados.put(nomeCliente, outputCliente);
		}
		
		return contemNome;
	}

	public ServerSocket getServidor() {
		return servidor;
	}

	public List<OutputStream> getCanaisClientesConectados() {
		return canaisClientesConectados;
	}
	
	public List<String> getClientesConectados() {
		return clientesConectados;
	}

	public HashMap<String, OutputStream> getRelacaoClientesConectados() {
		return relacaoClientesConectados;
	}

	@Override
	public void close() throws IOException {
		servidor.close();
	}
}
